home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / wnos / wn941101 / mbuf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-10  |  11.6 KB  |  574 lines

  1. /* Primitive mbuf allocate/free routines */
  2.  
  3. #include <stdio.h>
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "proc.h"
  7. #include "config.h"
  8.  
  9. /* Interrupt buffer pool */
  10. int Nibufs = NIBUFS;            /* Number of interrupt buffers */
  11. unsigned Ibufsize = IBUFSIZE;   /* size to allocate */
  12. long Ibuffail;                   /* Allocate failures */
  13. int Intqlen = 0;                 /* Number of free mbufs on Intq */
  14. int Iminfree = -1;              /* minimum free buffers */
  15.  
  16. static struct mbuf *Garbq;      /* List of buffers freed at interrupt time */
  17. static struct mbuf *Intq;       /* Mbuf pool for interrupt handlers */
  18.  
  19. void refiq()
  20. {
  21. struct mbuf *bp;
  22. int i_state;
  23.  
  24.    /* Empty the garbage */
  25.    if(Garbq != NULLBUF){
  26.       i_state = dirps();
  27.       bp = Garbq;
  28.       Garbq = NULLBUF;
  29.       restore(i_state);
  30.       free_p(bp);
  31.    }
  32.    /* Replenish interrupt buffer pool */
  33.    while(Intqlen < Nibufs){
  34.       if((bp = alloc_mbuf(Ibufsize)) == NULLBUF)
  35.          break;
  36.       i_state = dirps();
  37.       bp->next = Intq;
  38.       Intq = bp;
  39.       restore(i_state);
  40.       Intqlen++;
  41.    }
  42.    if(Iminfree == -1)
  43.       Iminfree = Intqlen;
  44. }
  45.  
  46. int
  47. dorefiq(int argc,char **argv,void *p)
  48. {
  49. struct mbuf *bp = 0, *bp1 = 0;
  50. int i_state = dirps();                   /* critical section             */
  51.  
  52.    if(Garbq != NULLBUF) {
  53.       bp = Garbq;
  54.       Garbq = NULLBUF;
  55.    }
  56.    bp1 = Intq;
  57.    Intq = NULLBUF;
  58.    Intqlen = 0;
  59. /*
  60.    Iminfree = -1;
  61. */
  62.    restore(i_state);
  63.    free_p(bp1);
  64.    free_p(bp);
  65.    refiq();
  66.    return 0;
  67. }
  68.  
  69. /* Allocate mbuf with associated buffer of 'size' bytes. If interrupts
  70.  * are enabled, use the regular heap. If they're off, use the special
  71.  * interrupt buffer pool.
  72.  */
  73. struct mbuf *
  74. alloc_mbuf(int16 size)
  75. {
  76. struct mbuf *bp;
  77.  
  78.    if(istate()){
  79.       /* Interrupts are enabled, use the heap normally */
  80.       if((bp = (struct mbuf *)mxallocw((unsigned)(size + sizeof(struct mbuf)))) == NULLBUF)
  81.          return NULLBUF;
  82.  
  83.       /* Clear just the header portion
  84.        * not necessary cuz WNOS always calls 'calloc'
  85.        *
  86.       memset((char *)bp,0,sizeof(struct mbuf));
  87.        *
  88.        */
  89.  
  90.       if((bp->size = size) != 0)
  91.          bp->data = (char *)(bp + 1);
  92.       bp->refcnt++;
  93.    } else {
  94.       /* Interrupts are off, use special interrupt buffer pool */
  95.       if(size > Ibufsize || Intq == NULLBUF) {
  96.          Ibuffail++;
  97.          return NULLBUF;
  98.       }
  99.       bp = Intq;
  100.       Intq = bp->next;
  101.       bp->next = NULLBUF;
  102.       Intqlen--;
  103.    }
  104.    if(Intqlen < Iminfree)
  105.       Iminfree = Intqlen;
  106.    return bp;
  107. }
  108.  
  109. /* Allocate mbuf, waiting if memory is unavailable */
  110. struct mbuf *
  111. ambufw(size)
  112. int16 size;
  113. {
  114.     struct mbuf *bp =
  115.         (struct mbuf *)mxallocw((unsigned)(size + sizeof(struct mbuf)));
  116.  
  117.     /* Clear just the header portion
  118.      * not necessary cuz WNOS always calls 'calloc'
  119.      *
  120.     memset((char *)bp,0,sizeof(struct mbuf));
  121.      *
  122.      */
  123.  
  124.     if((bp->size = size) != 0)
  125.         bp->data = (char *)(bp + 1);
  126.  
  127.     bp->refcnt++;
  128.  
  129.     if(Intqlen < Iminfree)
  130.         Iminfree = Intqlen;
  131.  
  132.     return bp;
  133. }
  134.  
  135. /* Decrement the reference pointer in an mbuf. If it goes to zero,
  136.  * free all resources associated with mbuf.
  137.  * Return pointer to next mbuf in packet chain
  138.  */
  139. struct mbuf *
  140. free_mbuf(bp)
  141. register struct mbuf *bp;
  142. {
  143.     struct mbuf *bp1 = NULLBUF;
  144.  
  145.     if(bp != NULLBUF){
  146.         bp1 = bp->next;
  147.         if(istate()){
  148.             /* Follow indirection, if any */
  149.             free_mbuf(bp->dup);
  150.  
  151.             /* If reference count has gone to zero, put it back on the heap */
  152.             if(--bp->refcnt <= 0)
  153.                  xfree((char *)bp);
  154.         } else {
  155.             /* Quickly put buffer on garbage list, where it will
  156.              * be freed by refiq() later with interrupts enabled
  157.              */
  158.              bp->next = Garbq;
  159.              Garbq = bp;
  160.         }
  161.     }
  162.     return bp1;
  163. }
  164.  
  165. /* Free packet (a chain of mbufs). Return pointer to next packet on queue,
  166.  * if any
  167.  */
  168. struct mbuf *
  169. free_p(bp)
  170. struct mbuf *bp;
  171. {
  172.     struct mbuf *abp;
  173.  
  174.     if(bp == NULLBUF)
  175.         return NULLBUF;
  176.     abp = bp->anext;
  177.     while(bp != NULLBUF)
  178.         bp = free_mbuf(bp);
  179.     return abp;
  180. }
  181.  
  182. /* Free entire queue of packets (of mbufs) */
  183. void
  184. free_q(q)
  185. struct mbuf **q;
  186. {
  187.     struct mbuf *bp;
  188.  
  189.     while((bp = dequeue(q)) != NULLBUF)
  190.         free_p(bp);
  191. }
  192.  
  193. /* Count up the total number of bytes in a packet */
  194. int16
  195. len_p(bp)
  196. struct mbuf *bp;
  197. {
  198.     int16 cnt = 0;
  199.  
  200.     while(bp != NULLBUF){
  201.         cnt += bp->cnt;
  202.         bp = bp->next;
  203.     }
  204.     return cnt;
  205. }
  206.  
  207. /* Count up the number of packets in a queue */
  208. int16
  209. len_q(bp)
  210. struct mbuf *bp;
  211. {
  212.     int16 cnt;
  213.  
  214.     for(cnt = 0; bp != NULLBUF; cnt++, bp = bp->anext) ;
  215.     return cnt;
  216. }
  217.  
  218. /* Trim mbuf to specified length by lopping off end */
  219. void
  220. trim_mbuf(bpp,length)
  221. struct mbuf **bpp;
  222. int16 length;
  223. {
  224.     int16 tot = 0;
  225.     struct mbuf *bp;
  226.  
  227.     if(bpp == NULLBUFP || *bpp == NULLBUF)
  228.         return; /* Nothing to trim */
  229.  
  230.     if(length == 0){
  231.         /* Toss the whole thing */
  232.         free_p(*bpp);
  233.         *bpp = NULLBUF;
  234.         return;
  235.     }
  236.     /* Find the point at which to trim. If length is greater than
  237.      * the packet, we'll just fall through without doing anything
  238.      */
  239.     for(bp = *bpp; bp != NULLBUF; bp = bp->next) {
  240.         if(tot + bp->cnt < length){
  241.             tot += bp->cnt;
  242.         } else {
  243.             /* Cut here */
  244.             bp->cnt = length - tot;
  245.             free_p(bp->next);
  246.             bp->next = NULLBUF;
  247.             break;
  248.         }
  249.     }
  250. }
  251.  
  252. /* Duplicate/enqueue/dequeue operations based on mbufs */
  253.  
  254. /* Duplicate first 'cnt' bytes of packet starting at 'offset'.
  255.  * This is done without copying data; only the headers are duplicated,
  256.  * but without data segments of their own. The pointers are set up to
  257.  * share the data segments of the original copy. The return pointer is
  258.  * passed back through the first argument, and the return value is the
  259.  * number of bytes actually duplicated.
  260.  */
  261. int16
  262. dup_p(hp,bp,offset,cnt)
  263. struct mbuf **hp;
  264. struct mbuf *bp;
  265. int16 offset;
  266. int16 cnt;
  267. {
  268.     struct mbuf *cp;
  269.     int16 tot = 0;
  270.  
  271.     if(cnt == 0 || bp == NULLBUF || hp == NULLBUFP) {
  272.         if(hp != NULLBUFP)
  273.         *hp = NULLBUF;
  274.         return 0;
  275.     }
  276.     if((*hp = cp = alloc_mbuf(0)) == NULLBUF) {
  277.         return 0;
  278.     }
  279.     /* Skip over leading mbufs that are smaller than the offset */
  280.     while(bp != NULLBUF && bp->cnt <= offset) {
  281.         offset -= bp->cnt;
  282.         bp = bp->next;
  283.     }
  284.     if(bp == NULLBUF) {
  285.         free_mbuf(cp);
  286.         *hp = NULLBUF;
  287.         return 0;       /* Offset was too big */
  288.     }
  289.  
  290.     for(;;){
  291.         /* Make sure we get the original, "real" buffer (i.e. handle the
  292.         * case of duping a dupe)
  293.         */
  294.         if(bp->dup != NULLBUF)
  295.             cp->dup = bp->dup;
  296.         else
  297.             cp->dup = bp;
  298.  
  299.         /* Increment the duplicated buffer's reference count */
  300.         cp->dup->refcnt++;
  301.  
  302.         cp->data = bp->data + offset;
  303.         cp->cnt = min(cnt,bp->cnt - offset);
  304.         offset = 0;
  305.         cnt -= cp->cnt;
  306.         tot += cp->cnt;
  307.         bp = bp->next;
  308.         if(cnt == 0 || bp == NULLBUF || (cp->next = alloc_mbuf(0)) == NULLBUF)
  309.             break;
  310.         cp = cp->next;
  311.     }
  312.     return tot;
  313. }
  314.  
  315. /* Copy first 'cnt' bytes of packet into a new, single mbuf */
  316. struct mbuf *
  317. copy_p(bp,cnt)
  318. struct mbuf *bp;
  319. int16 cnt;
  320. {
  321.     struct mbuf *cp;
  322.     char *wp;
  323.     int16 n;
  324.  
  325.     if(bp == NULLBUF || cnt == 0 || (cp = alloc_mbuf(cnt)) == NULLBUF)
  326.         return NULLBUF;
  327.     wp = cp->data;
  328.     while(cnt != 0 && bp != NULLBUF){
  329.         n = min(cnt,bp->cnt);
  330.         memcpy(wp,bp->data,n);
  331.         wp += n;
  332.         cp->cnt += n;
  333.         cnt -= n;
  334.         bp = bp->next;
  335.     }
  336.     return cp;
  337. }
  338.  
  339. /* Copy and delete "cnt" bytes from beginning of packet. Return number of
  340.  * bytes actually pulled off
  341.  */
  342. int16
  343. pullup(bph,buf,cnt)
  344. struct mbuf **bph;
  345. char *buf;
  346. int16 cnt;
  347. {
  348.     struct mbuf *bp;
  349.     int16 n, tot = 0;
  350.  
  351.     if(bph == NULLBUFP)
  352.         return 0;
  353.     while(cnt != 0 && (bp = *bph) != NULLBUF){
  354.         n = min(cnt,bp->cnt);
  355.         if(buf != NULLCHAR){
  356.             if(n == 1)      /* Common case optimization */
  357.                 *buf = *bp->data;
  358.             else if(n > 1)
  359.                 memcpy(buf,bp->data,n);
  360.                 buf += n;
  361.             }
  362.             tot += n;
  363.             cnt -= n;
  364.             bp->data += n;
  365.             bp->cnt -= n;
  366.             if(bp->cnt == 0){
  367.                 /* If this is the last mbuf of a packet but there
  368.                  * are others on the queue, return a pointer to
  369.                  * the next on the queue. This allows pullups to
  370.                  * to work on a packet queue
  371.                  */
  372.             if(bp->next == NULLBUF && bp->anext != NULLBUF) {
  373.                 *bph = bp->anext;
  374.                 free_mbuf(bp);
  375.             } else
  376.                 *bph = free_mbuf(bp);
  377.         }
  378.     }
  379.     return tot;
  380. }
  381.  
  382. /* Append mbuf to end of mbuf chain */
  383. void
  384. append(bph,bp)
  385. struct mbuf **bph;
  386. struct mbuf *bp;
  387. {
  388.     struct mbuf *p;
  389.  
  390.     if(bph == NULLBUFP || bp == NULLBUF)
  391.         return;
  392.     if(*bph == NULLBUF) {
  393.         /* First one on chain */
  394.         *bph = bp;
  395.     } else {
  396.         for(p = *bph ; p->next != NULLBUF ; p = p->next) ;
  397.         p->next = bp;
  398.     }
  399. }
  400.  
  401. /* Insert specified amount of contiguous new space at the beginning of an
  402.  * mbuf chain. If enough space is available in the first mbuf, no new space
  403.  * is allocated. Otherwise a mbuf of the appropriate size is allocated and
  404.  * tacked on the front of the chain.
  405.  *
  406.  * This operation is the logical inverse of pullup(), hence the name.
  407.  */
  408. struct mbuf *
  409. pushdown(bp,size)
  410. struct mbuf *bp;
  411. int16 size;
  412. {
  413.     struct mbuf *nbp;
  414.  
  415.     /* Check that bp is real, that it hasn't been duplicated, and
  416.      * that it itself isn't a duplicate before checking to see if
  417.      * there's enough space at its front.
  418.      */
  419.     if(bp != NULLBUF && bp->refcnt == 1 && bp->size != 0
  420.       && bp->data - (char *)(bp+1) >= size) {
  421.         /* No need to alloc new mbuf, just adjust this one */
  422.         bp->data -= size;
  423.         bp->cnt += size;
  424.     } else {
  425.         nbp = ambufw(size);
  426.         nbp->next = bp;
  427.         nbp->cnt = size;
  428.         bp = nbp;
  429.     }
  430.     return bp;
  431. }
  432.  
  433. /* Append packet to end of packet queue */
  434. void
  435. enqueue(q,bp)
  436. struct mbuf **q;
  437. struct mbuf *bp;
  438. {
  439.     struct mbuf *p;
  440.     int i_state;
  441.  
  442.     if(q == NULLBUFP || bp == NULLBUF)
  443.         return;
  444.     i_state = dirps();
  445.     if(*q == NULLBUF) {
  446.         /* List is empty, stick at front */
  447.         *q = bp;
  448.     } else {
  449.         for(p = *q ; p->anext != NULLBUF ; p = p->anext) ;
  450.         p->anext = bp;
  451.     }
  452.     restore(i_state);
  453.     psignal(q,1);
  454. }
  455.  
  456. /* Unlink a packet from the head of the queue */
  457. struct mbuf *
  458. dequeue(q)
  459. struct mbuf **q;
  460. {
  461.     struct mbuf *bp;
  462.     int i_state;
  463.  
  464.     if(q == NULLBUFP)
  465.         return NULLBUF;
  466.     i_state = dirps();
  467.     if((bp = *q) != NULLBUF) {
  468.         *q = bp->anext;
  469.         bp->anext = NULLBUF;
  470.     }
  471.     restore(i_state);
  472.     return bp;
  473. }
  474.  
  475. /* Copy user data into an mbuf */
  476. struct mbuf *
  477. qdata(data,cnt)
  478. char *data;
  479. int16 cnt;
  480. {
  481.     struct mbuf *bp;
  482.  
  483.     bp = ambufw(cnt);
  484.     memcpy(bp->data,data,cnt);
  485.     bp->cnt = cnt;
  486.     return bp;
  487. }
  488.  
  489. #ifdef VANESSA
  490. /* Copy mbuf data into user buffer */
  491. int16
  492. dqdata(bp,buf,cnt)
  493. struct mbuf *bp;
  494. char *buf;
  495. unsigned cnt;
  496. {
  497.     int16 tot = 0;
  498.     unsigned n;
  499.     struct mbuf *bp1;
  500.  
  501.     if(buf == NULLCHAR)
  502.         return 0;
  503.  
  504.     for(bp1 = bp;bp1 != NULLBUF; bp1 = bp1->next) {
  505.         n = min(bp1->cnt,cnt);
  506.         memcpy(buf,bp1->data,n);
  507.         cnt -= n;
  508.         buf += n;
  509.         tot += n;
  510.     }
  511.     free_p(bp);
  512.     return tot;
  513. }
  514. #endif
  515.  
  516. /* Pull a 32-bit integer in host order from buffer in network byte order.
  517.  * On error, return 0. Note that this is indistinguishable from a normal
  518.  * return.
  519.  */
  520. int32
  521. pull32(bpp)
  522. struct mbuf **bpp;
  523. {
  524.     char buf[4];
  525.  
  526.     if(pullup(bpp,buf,4) != 4) {
  527.         /* Return zero if insufficient buffer */
  528.         return 0;
  529.     }
  530.     return get32(buf);
  531. }
  532.  
  533. /* Pull a 16-bit integer in host order from buffer in network byte order.
  534.  * Return -1 on error
  535.  */
  536. int16
  537. pull16(bpp)
  538. struct mbuf **bpp;
  539. {
  540.     char buf[2];
  541.  
  542.     if(pullup(bpp,buf,2) != 2){
  543.         /* Return -1 if insufficient buffer */
  544.         return -1;
  545.     }
  546.     return get16(buf);
  547. }
  548.  
  549. /* Pull single character from mbuf */
  550. int
  551. pullchar(bpp)
  552. struct mbuf **bpp;
  553. {
  554.     char c;
  555.  
  556.     if(pullup(bpp,&c,1) != 1)
  557.         return -1;              /* Nothing left */
  558.     return (int)uchar(c);
  559. }
  560.  
  561. int
  562. write_p(fp,bp)
  563. FILE *fp;
  564. struct mbuf *bp;
  565. {
  566.     while(bp != NULLBUF){
  567.         if(fwrite(bp->data,1,bp->cnt,fp) != bp->cnt)
  568.             return -1;
  569.         bp = bp->next;
  570.     }
  571.     return 0;
  572. }
  573.  
  574.